package jmine.selenium.services;

import java.net.URL;

import jmine.selenium.WebDriverFactory;
import jmine.tec.di.annotation.Injected;
import jmine.tec.services.annotations.Execution;
import jmine.tec.services.annotations.Input;
import jmine.tec.services.annotations.Output;
import jmine.tec.services.annotations.ServiceImplementor;
import jmine.tec.services.api.ActionsEnum;
import jmine.tec.services.api.ServiceExecutionException;
import jmine.tec.test.testcase.TestCase;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverBackedSelenium;

import com.thoughtworks.selenium.Selenium;

/**
 * Implementação base de serviços de selenium que devem ser utilizados para abrir a pagina inicial da aplicação.
 * 
 * @author Rafael Volpato
 * @date Dec 3, 2010
 */
@ServiceImplementor(action = ActionsEnum.PRE_REQ)
public abstract class SeleniumApplicationService extends TestCase {

    public static final String APPLICATION_URL = "URL";

    public static final String NEW_WINDOW = "Nova janela";

    public static final String IDENTIFICADOR = "Selenium Session";

    public static final String DEFAULT_SESSION = "$session";

    private WebDriverFactory webDriverFactory;

    private URL applicationURL;

    private boolean newWindow;

    /**
     * @param webDriverFactory the webDriverFactory to set
     */
    @Injected
    public final void setWebDriverFactory(WebDriverFactory webDriverFactory) {
        this.webDriverFactory = webDriverFactory;
    }

    /**
     * Informa a URL da aplicação a ser acessada.
     * 
     * @param applicationURL applicationURL
     */
    @Input(fieldName = APPLICATION_URL)
    public void setApplicationURL(URL applicationURL) {
        this.applicationURL = applicationURL;
    }

    /**
     * Informa se ao abrir a pagina da aplicação essa deve ser aberta em uma nova janela do browser.
     * 
     * @param newWindow newWindow
     */
    @Input(fieldName = NEW_WINDOW, defaultValue = "false")
    public void setNewWindow(boolean newWindow) {
        this.newWindow = newWindow;
    }

    /**
     * Retorna uma instancia de {@link WebDriver}. Se o atributo newWindow for <code>false</code> esse metodo retorna o driver que foi
     * injetado pelo spring (singleton), caso contrario cria uma nova instancia.
     * 
     * @return uma instancia de {@link WebDriver}
     * @throws ServiceExecutionException se ocorrer algum erro
     */
    private WebDriver getWebDriver() throws ServiceExecutionException {
        WebDriver webDriver = null;

        if (this.newWindow) {
            webDriver = this.webDriverFactory.getNewWebDriver();
        } else {
            webDriver = this.webDriverFactory.getWebDriver();
        }

        return webDriver;
    }

    /**
     * Abre a primeira pagina da aplicação (provavelmente criando uma nova instancia de selenium).
     * 
     * @return o selenium criado
     * @throws ServiceExecutionException se ocorrer algum erro
     */
    @Execution
    @Output(propertyName = IDENTIFICADOR)
    public final Selenium execute() throws ServiceExecutionException {
        Selenium selenium = new WebDriverBackedSelenium(this.getWebDriver(), applicationURL.toString());

        this.openApplication(selenium);

        return selenium;
    }

    /**
     * Implementação que deve abrir a pagina principal do sistema.
     * 
     * @param selenium selenium
     */
    protected abstract void openApplication(Selenium selenium);
}
